<?php
/**
 * DMFramework
 * 
 * @license Copyright 2012 Dillen Meijboom under the Apache license version 2.0 (http://apache.org/licenses/LICENSE-2.0)
 * @author Dillen Meijboom <info@dillenm.nl>
 * @url http://dmframework.nl
 */

/**
 * The cache class can be used to cache certain items and retrieve them later on
 * thumbnails can be saved for a certain time for instance.
 * 
 * @license Copyright 2012 Dillen Meijboom under the Apache license version 2.0 (http://apache.org/licenses/LICENSE-2.0)
 * @author Dillen Meijboom <info@dillenm.nl>
 * @package System.Library
 */
class Dmf_Cache
{
    /**
     * Local cache
     * 
     * @var array
     */
    private $_local_cache = array();
    
    /**
     * Configuration
     * 
     * @var array
     */
    private $_config = array(
        'save_path' => 'system/cache/',
        'prefix'    => 'Dmf_Cached_Item_'
    );
    
    /**
     * Constructor 
     */
    public function __construct()
    {
        if ( isset( Dmf_Application::getInstance()->getConfig()->asObject()->config->cache ) )
        {
            $this->_config = array_merge( $this->_config, Dmf_Application::getInstance()->getConfig()->asObject()->config->cache->asArray() );
        }
    }
    
    /**
     * Set config option
     * 
     * @param string $index
     * @param string $value 
     */
    public function setOption( $index, $value )
    {
        $this->_config[ $index ] = $value;
    }
    
    /**
     * Get file name
     * 
     * @param string $id
     * @return string
     */
    private function _getFilename( $id )
    {
        return $this->_config['save_path'] . sha1( $this->_config['prefix'] . $id );
    }
    
    /**
     * Write to cached file
     * 
     * @param string $id
     * @throws Exception 
     */
    private function _writeToFile( $id )
    {
        if ( ! is_writable( $this->_getFilename( $id ) ) && file_exists( $this->_getFilename( $id ) ) )
        {
            throw new Exception( 'Cache file: "' . $this->_getFilename( $id ) . '" is not writable.' );
        }
        
        file_put_contents( $this->_getFilename( $id ), serialize( $this->_local_cache[ $id ] ) );    
    }
    
    /**
     * Read cached file
     * 
     * @param string $id
     * @return array
     */
    private function _readFile( $id )
    {
        $filename = $this->_getFilename( $id );
        
        if ( file_exists( $filename ) )
        {
            return @unserialize( file_get_contents( $filename ) );
        }
        else
        {
            return array();
        }
    }
    
    /**
     * Save cached item
     * 
     * @param string $id
     * @param mixed $value
     * @param int $time 
     */
    public function save( $id, $value, $time = 3600 )
    {
        $this->_local_cache[ $id ] = array(
            'time' => time(),
            'expire' => $time,
            'value' => serialize( $value )
        );
        
        $this->_writeToFile( $id );
    }
    
    /**
     * Checks if item is still cached
     * 
     * @param int $id
     * @return boolean 
     */
    public function isCached( $id )
    {
        if ( ! file_exists( $this->_getFilename( $id ) ) )
        {
            return false;
        }
        
        $info = isset( $this->_local_cache[ $id ] ) ? $this->_local_cache[ $id ] : $this->_readFile( $id );
        
        if ( time() >= ( $info['time'] + $info['expire'] ) )
        {
            if ( is_writable( $this->_getFilename( $id ) ) )
            {
                unlink( $this->_getFilename( $id ) );
            }
            
            return false;
        }
        
        return true;
    }
    
    /**
     * Delete cached item
     * 
     * @param int $id 
     */
    public function delete( $id )
    {
        if ( ! $this->isCached( $id ) || ! file_exists( $this->_getFilename( $id ) ) )
        {
            return;
        }
        
        if ( is_writable( $this->_getFilename( $id ) ) )
        {
            unlink( $this->_getFilename( $id ) );
        }
    }
    
    /**
     * Get cached item
     * 
     * @param int $id
     * @return boolean 
     */
    public function get( $id )
    {
        if ( ! $this->isCached( $id ) )
        {
            return false;
        }
        
        $info = isset( $this->_local_cache[ $id ] ) ? $this->_local_cache[ $id ] : $this->_readFile( $id );
        
        return @unserialize( $info['value'] );
    }
    
    /**
     * Clear entire cache 
     */
    public function clear()
    {
        $this->_local_cache = array();
        
        foreach( scandir( $this->_config['save_path'] ) as $file )
        {
            $rfile = $this->_config['save_path'] . $file;
            
            if ( filetype( $rfile ) == 'file' && is_writable( $rfile ) )
            {
                unlink( $rfile );
            }
        }
    }
}